home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Players / DDrawXCL / vidplay.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  33.7 KB  |  1,118 lines

  1. //------------------------------------------------------------------------------
  2. // File: VidPlay.cpp
  3. //
  4. // Desc: DirectShow sample code - video (DVD and file) playback class.
  5. //
  6. // Copyright (c) 1993-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include <streams.h>
  11. #include <windows.h>
  12.  
  13. #include "mpconfig.h"
  14. #include "VidPlay.h"
  15.  
  16.  
  17. //
  18. // CBaseVideoPlayer constructor
  19. //
  20. CBaseVideoPlayer::CBaseVideoPlayer()
  21. {
  22.     m_eState = Uninitialized ;
  23.     ZeroMemory(m_achFileName, sizeof(m_achFileName)) ;
  24.     
  25.     m_pGraph = NULL ;
  26.     m_pMC = NULL ;
  27.     m_pME = NULL ;
  28.     
  29.     m_dwColorKey = 253 ;  // magenta by default
  30. }
  31.  
  32.  
  33. //
  34. // CBaseVideoPlayer destructor
  35. //
  36. CBaseVideoPlayer::~CBaseVideoPlayer()
  37. {
  38.     ReleaseInterfaces() ;
  39. }
  40.  
  41.  
  42. //
  43. // CBaseVideoPlayer::GetInterfaces(): Gets the standard interfaces required for
  44. // playing back through a filter graph
  45. //
  46. HRESULT CBaseVideoPlayer::GetInterfaces(HWND hWndApp)
  47. {
  48.     HRESULT  hr ;
  49.     hr = m_pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&m_pMC) ;
  50.     ASSERT(SUCCEEDED(hr) && m_pMC) ;
  51.     
  52.     hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (LPVOID *)&m_pME) ;
  53.     ASSERT(SUCCEEDED(hr) && m_pME) ;
  54.     
  55.     //
  56.     // Also set up the event notification so that the main window gets
  57.     // informed about all that we care about during playback.
  58.     //
  59.     hr = m_pME->SetNotifyWindow((OAHWND) hWndApp, WM_PLAY_EVENT, (LONG_PTR) m_pME) ;
  60.     ASSERT(SUCCEEDED(hr)) ;
  61.     
  62.     m_eState = Stopped ;  // graph has been built
  63.     
  64.     return S_OK ;
  65. }
  66.  
  67.  
  68. //
  69. // CBaseVideoPlayer::ReleaseInterfaces(): Let go of the standard interfaces taken for playback.
  70. //
  71. void CBaseVideoPlayer::ReleaseInterfaces(void)
  72. {
  73.     DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::ReleaseInterfaces() entered"))) ;
  74.  
  75.     if (m_pMC) {
  76.         m_pMC->Release() ;
  77.         m_pMC = NULL ;
  78.     }
  79.     if (m_pME) {
  80.         // clear any already set notification arrangement
  81.         m_pME->SetNotifyWindow(NULL, WM_PLAY_EVENT, (LONG_PTR) m_pME) ;
  82.         m_pME->Release() ;
  83.         m_pME = NULL ;
  84.     }
  85.     
  86.     m_eState = Uninitialized ;  // no graph available
  87. }
  88.  
  89.  
  90. //
  91. // CBaseVideoPlayer::WaitForState(): Wait for the state to change to the given one.
  92. //
  93. void CBaseVideoPlayer::WaitForState(FILTER_STATE State)
  94. {
  95.     // Make sure we have switched to the required state
  96.     LONG   lfs ;
  97.     do
  98.     {
  99.         m_pMC->GetState(10, &lfs) ;
  100.     } while (State != lfs) ;
  101. }
  102.  
  103.  
  104. //
  105. // CBaseVideoPlayer::Play(): Plays the filter graph (and waits to really start playing)
  106. //
  107. BOOL CBaseVideoPlayer::Play(void)
  108. {
  109.     DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Play() entered"))) ;
  110.     
  111.     if (! IsGraphReady() )
  112.     {
  113.         DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
  114.         return FALSE ;
  115.     }
  116.     HRESULT  hr = m_pMC->Run() ;
  117.     if (FAILED(hr))
  118.     {
  119.         DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Run() failed (Error 0x%lx)"), hr)) ;
  120.         return FALSE ;
  121.     }
  122.     WaitForState(State_Running) ;
  123.     
  124.     // Some state changes now
  125.     m_eState = Playing ;
  126.     
  127.     return TRUE ;  // success
  128. }
  129.  
  130.  
  131. //
  132. // CBaseVideoPlayer::Pause(): Pauses/Cues the filter graph (and waits to really pause)
  133. //
  134. BOOL CBaseVideoPlayer::Pause(void)
  135. {
  136.     DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Pause() entered"))) ;
  137.     
  138.     if (! IsGraphReady() )
  139.     {
  140.         DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
  141.         return FALSE ;
  142.     }
  143.     HRESULT  hr = m_pMC->Pause() ;
  144.     if (FAILED(hr))
  145.     {
  146.         DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Pause() failed (Error 0x%lx)"), hr)) ;
  147.         return FALSE ;
  148.     }
  149.     WaitForState(State_Paused) ;
  150.     
  151.     // Some state changes now
  152.     m_eState = Paused ;
  153.     
  154.     return TRUE ;  // success
  155. }
  156.  
  157.  
  158. //
  159. // CBaseVideoPlayer::Stop(): Stops the filter graph (and waits to really stop)
  160. //
  161. BOOL CBaseVideoPlayer::Stop(void)
  162. {
  163.     DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Stop() entered"))) ;
  164.     
  165.     if (! IsGraphReady() )
  166.     {
  167.         DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
  168.         return FALSE ;
  169.     }
  170.     HRESULT  hr = m_pMC->Stop() ;
  171.     if (FAILED(hr))
  172.     {
  173.         DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Stop() failed (Error 0x%lx)"), hr)) ;
  174.         return FALSE ;
  175.     }
  176.     WaitForState(State_Stopped) ;
  177.     
  178.     // Some state changes now
  179.     m_eState = Stopped ;
  180.     
  181.     return TRUE ;  // success
  182. }
  183.  
  184.  
  185. //
  186. // CBaseVideoPlayer::GetColorKey(): Returns color key to the app so that other 
  187. // components (here the DDraw object) can be told about it.
  188. //
  189. HRESULT CBaseVideoPlayer::GetColorKey(DWORD *pdwColorKey)
  190. {
  191.     DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::GetColorKey() entered"))) ;
  192.     
  193.     if (! IsGraphReady() )
  194.         return E_UNEXPECTED ;
  195.     
  196.     *pdwColorKey = m_dwColorKey ;  // use the cached color key info
  197.     return S_OK ;
  198. }
  199.  
  200.  
  201.  
  202. //
  203. // CDVDPlayer constructor
  204. //
  205. CDVDPlayer::CDVDPlayer()
  206. {
  207.     DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer c-tor entered"))) ;
  208.     
  209.     m_pDvdGB = NULL ;
  210.     m_pDvdC  = NULL ;
  211.     m_pDvdI  = NULL ;
  212. }
  213.  
  214.  
  215. //
  216. // CDVDPlayer destructor
  217. //
  218. CDVDPlayer::~CDVDPlayer()
  219. {
  220.     DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer d-tor entered"))) ;
  221.     
  222.     ReleaseInterfaces() ;
  223.     
  224.     if (m_pDvdGB)
  225.         m_pDvdGB->Release() ;
  226.     
  227.     DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer d-tor exiting..."))) ;
  228. }
  229.  
  230.  
  231. //
  232. // CDVDPlayer::Initialize(): Creates a DVD graph builder object for later building
  233. // a filter graph.
  234. //
  235. BOOL CDVDPlayer::Initialize(void)
  236. {
  237.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::Initialize() entered"))) ;
  238.     
  239.     //
  240.     // Now instantiate the DVD Graph Builder object and start working
  241.     //
  242.     HRESULT hr = CoCreateInstance(CLSID_DvdGraphBuilder, NULL, CLSCTX_INPROC, 
  243.         IID_IDvdGraphBuilder, (LPVOID *)&m_pDvdGB) ;
  244.     if (FAILED(hr) || NULL == m_pDvdGB)
  245.     {
  246.         DbgLog((LOG_ERROR, 0, 
  247.             TEXT("ERROR: DirectShow DVD software not installed properly (Error 0x%lx)"), hr)) ;
  248.         return FALSE ;
  249.     }
  250.     
  251.     return TRUE;
  252. }
  253.  
  254.  
  255. //
  256. // CDVDPlayer::BuildGraph(): Builds a filter graph for playing back the specified
  257. // DVD title/file.  Also gets some interfaces that are required for controlling 
  258. // playback.
  259. //
  260. HRESULT CDVDPlayer::BuildGraph(HWND hWndApp, LPDIRECTDRAW pDDObj, LPDIRECTDRAWSURFACE pDDPrimary)
  261. {
  262.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::BuildGraph() entered"))) ;
  263.  
  264.     HRESULT     hr ;
  265.     
  266.     // First release any existing interface pointer(s)
  267.     ReleaseInterfaces() ;
  268.     SetColorKey(253) ;  // default magenta for 8bpp
  269.     
  270.     // Check if a DVD-Video volume name has been specified; if so, use that
  271.     WCHAR    achwFileName[MAX_PATH] ;
  272.     LPCWSTR  lpszwFileName = NULL ;  // by default
  273.     if (lstrlen(GetFileName()) > 0)  // if something was specified before
  274.     {
  275. #ifdef UNICODE
  276.         lstrcpy(achwFileName, GetFileName()) ;
  277. #else
  278.         MultiByteToWideChar(CP_ACP, 0, GetFileName(), -1, achwFileName, MAX_PATH) ;
  279. #endif // UNICODE
  280.         
  281.         lpszwFileName = achwFileName ;
  282.     }
  283.     DbgLog((LOG_TRACE, 5, TEXT("DVD file <%s> will be played"), GetFileName())) ;
  284.     
  285.     // Set DDraw object and surface on DVD graph builder before starting to build graph
  286.     IDDrawExclModeVideo  *pDDXMV ;
  287.     hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
  288.     if (FAILED(hr) || NULL == pDDXMV)
  289.     {
  290.         DbgLog((LOG_ERROR, 0, 
  291.             TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
  292.         return hr ;
  293.     }
  294.     hr = pDDXMV->SetDDrawObject(pDDObj) ;
  295.     if (FAILED(hr))
  296.     {
  297.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetDDrawObject() failed (Error 0x%lx)"), hr)) ;
  298.         pDDXMV->Release() ;  // release before returning
  299.         return hr ;
  300.     }
  301.     hr = pDDXMV->SetDDrawSurface(pDDPrimary) ;
  302.     if (FAILED(hr))
  303.     {
  304.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetDDrawSurface() failed (Error 0x%lx)"), hr)) ;
  305.         pDDXMV->SetDDrawObject(NULL) ;  // to reset
  306.         pDDXMV->Release() ;  // release before returning
  307.         return hr ;
  308.     }
  309.     pDDXMV->Release() ;  // done with the interface
  310.     
  311.     // Build the graph
  312.     AM_DVD_RENDERSTATUS   Status ;
  313.     TCHAR                 achBuffer[1000] ;
  314.     hr = m_pDvdGB->RenderDvdVideoVolume(lpszwFileName,
  315.         AM_DVD_HWDEC_PREFER, &Status) ;
  316.     if (FAILED(hr))
  317.     {
  318.         AMGetErrorText(hr, achBuffer, sizeof(achBuffer)/sizeof(achBuffer[0])) ;
  319.         MessageBox(hWndApp, achBuffer, TEXT("Error"), MB_OK) ;
  320.         return hr ;
  321.     }
  322.     if (S_FALSE == hr)  // if partial success
  323.     {
  324.         if (0 == GetStatusText(&Status, achBuffer, sizeof(achBuffer)))
  325.         {
  326.             lstrcpy(achBuffer, TEXT("An unknown error has occurred")) ;
  327.         }
  328.         lstrcat(achBuffer, TEXT("\n\nDo you still want to continue?")) ;
  329.         if (IDNO == MessageBox(hWndApp, achBuffer, TEXT("Warning"), MB_YESNO))
  330.         {
  331.             return E_FAIL ;
  332.         }
  333.     }
  334.     
  335.     GetInterfaces(hWndApp) ;
  336.     
  337.     hr = GetColorKeyInternal() ;
  338.     ASSERT(SUCCEEDED(hr)) ;
  339.  
  340.     return S_OK ;
  341. }
  342.  
  343.  
  344. //
  345. // CDVDPlayer::GetInterfaces(): Gets some interfaces useful for DVD title playback
  346. //
  347. HRESULT CDVDPlayer::GetInterfaces(HWND hWndApp)
  348. {
  349.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetInterfaces() entered"))) ;
  350.  
  351.     HRESULT  hr ;
  352.     hr = m_pDvdGB->GetFiltergraph(&m_pGraph) ;
  353.     ASSERT(SUCCEEDED(hr) && m_pGraph) ;
  354.     
  355.     // Now get the DVD-specific interfaces (though we don't use them in this app).
  356.     hr = m_pDvdGB->GetDvdInterface(IID_IDvdControl2, (LPVOID *)&m_pDvdC) ;
  357.     ASSERT(SUCCEEDED(hr) && m_pDvdC) ;
  358.     
  359.     hr = m_pDvdGB->GetDvdInterface(IID_IDvdInfo2, (LPVOID *)&m_pDvdI) ;
  360.     ASSERT(SUCCEEDED(hr) && m_pDvdI) ;
  361.     
  362.     return CBaseVideoPlayer::GetInterfaces(hWndApp) ;  // get the standard interfaces
  363. }
  364.  
  365.  
  366. //
  367. // CDVDPlayer::ClearGraph(): Tears down the filter graph created by BuildGraph()
  368. // and also releases the DVD graph builder object.
  369. //
  370. HRESULT CDVDPlayer::ClearGraph()
  371. {
  372.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::ClearGraph() entered"))) ;
  373.     
  374.     ReleaseInterfaces() ;  // let go of the other interfaces
  375.     if (m_pDvdGB)
  376.     {
  377.         m_pDvdGB->Release() ;
  378.         m_pDvdGB = NULL ;
  379.     }
  380.     
  381.     return S_OK ;
  382.     
  383. }
  384.  
  385.  
  386. //
  387. // CDVDPlayer::GetColorKeyInternal(): Retrieves color key and stores it for later 
  388. // queries from the app.
  389. //
  390. HRESULT CDVDPlayer::GetColorKeyInternal(IBaseFilter *pOvM /* = NULL */)
  391. {
  392.     ASSERT(NULL == pOvM) ; // we don't need pOvM passed in
  393.     
  394.     // Get color key from MixerPinConfig interface via IDvdGraphBuilder
  395.     IMixerPinConfig2  *pMPC ;
  396.     DWORD              dwColorKey ;
  397.     HRESULT  hr = m_pDvdGB->GetDvdInterface(IID_IMixerPinConfig2, (LPVOID *) &pMPC) ;
  398.     if (SUCCEEDED(hr))
  399.     {
  400.         hr = pMPC->GetColorKey(NULL, &dwColorKey) ;
  401.         ASSERT(SUCCEEDED(hr)) ;
  402.         SetColorKey(dwColorKey) ;
  403.  
  404.         //  Set mode to stretch - that way we don't fight the overlay
  405.         //  mixer about the exact way to fix the aspect ratio
  406.         pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED);
  407.         pMPC->Release() ;
  408.     }
  409.     else
  410.     {
  411.         DbgLog((LOG_ERROR, 0, 
  412.             TEXT("WARNING: IDvdGraphBuilder::GetDvdInterface(IID_IMixerPinConfig2) failed (Error 0x%lx)"), hr)) ;
  413.         return hr ;
  414.     }
  415.     return S_OK ;
  416. }
  417.  
  418.  
  419. //
  420. // CDVDPlayer::GetNativeVideoData(): Retrieves the original video size from OverlayMixer's
  421. // IDDrawExclModeVideo interface.
  422. //
  423. HRESULT CDVDPlayer::GetNativeVideoData(DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwARX, DWORD *pdwARY)
  424. {
  425.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetNativeVideoData() entered"))) ;
  426.     
  427.     IDDrawExclModeVideo  *pDDXMV ;
  428.     HRESULT hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
  429.     if (FAILED(hr) || NULL == pDDXMV)
  430.     {
  431.         DbgLog((LOG_ERROR, 0, 
  432.             TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
  433.         return hr ;
  434.     }
  435.     hr = pDDXMV->GetNativeVideoProps(pdwWidth, pdwHeight, pdwARX, pdwARY) ;
  436.     if (FAILED(hr))
  437.     {
  438.         DbgLog((LOG_TRACE, 1, 
  439.             TEXT("WARNING: IDDrawExclModeVideo::GetNativeVideoProps() failed (Error 0x%lx)"), hr)) ;
  440.     }
  441.     
  442.     pDDXMV->Release() ;  // release before returning
  443.     
  444.     return hr ;
  445. }
  446.  
  447.  
  448. //
  449. // CDVDPlayer::SetVideoPosition(): Sets the source and destination rects on the 
  450. // OverlayMixer's IDDrawExclModeVideo interface .
  451. //
  452. HRESULT CDVDPlayer::SetVideoPosition(DWORD dwLeft, DWORD dwTop, DWORD dwWidth, DWORD dwHeight)
  453. {
  454.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::SetVideoPosition() entered"))) ;
  455.     
  456.     IDDrawExclModeVideo  *pDDXMV ;
  457.     HRESULT hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
  458.     if (FAILED(hr) || NULL == pDDXMV)
  459.     {
  460.         DbgLog((LOG_ERROR, 0, 
  461.             TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
  462.         return hr ;
  463.     }
  464.     
  465.     RECT  rectDest ;
  466.     SetRect(&rectDest, dwLeft, dwTop, dwLeft + dwWidth, dwTop + dwHeight) ;
  467.     // NULL or (0, 0, 10000, 10000) for full video
  468.     hr = pDDXMV->SetDrawParameters(NULL, &rectDest) ;
  469.     if (FAILED(hr))
  470.     {
  471.         DbgLog((LOG_TRACE, 1, 
  472.             TEXT("WARNING: IDDrawExclModeVideo::SetDrawParameters() failed (Error 0x%lx)"), hr)) ;
  473.     }
  474.     
  475.     pDDXMV->Release() ;  // release before returning
  476.     
  477.     return hr ;
  478. }
  479.  
  480.  
  481. //
  482. // CDVDPlayer::SetOverlayCallback(): Specify the pointer to the overlay notification
  483. // callback object which the OverlayMixer will call during playback.
  484. //
  485. HRESULT CDVDPlayer::SetOverlayCallback(IDDrawExclModeVideoCallback *pCallback)
  486. {
  487.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::SetOverlayCallback() entered"))) ;
  488.  
  489.     HRESULT  hr ;
  490.     IDDrawExclModeVideo  *pDDXMV ;
  491.     hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
  492.     if (FAILED(hr) || NULL == pDDXMV)
  493.     {
  494.         DbgLog((LOG_ERROR, 0, 
  495.             TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
  496.         return hr ;
  497.     }
  498.     hr = pDDXMV->SetCallbackInterface(pCallback, 0) ;
  499.     if (FAILED(hr))
  500.     {
  501.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetCallbackInterface() failed (Error 0x%lx)"), hr)) ;
  502.     }
  503.     pDDXMV->Release() ;  // done with the interface
  504.  
  505.     return hr ;
  506. }
  507.  
  508.  
  509. //
  510. // CDVDPlayer::ReleaseInterfaces(): Let go of the interfaces taken in BuildGraph()
  511. //
  512. void CDVDPlayer::ReleaseInterfaces(void)
  513. {
  514.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::ReleaseInterfaces() entered"))) ;
  515.     
  516.     if (m_pDvdC) {
  517.         m_pDvdC->Release() ;
  518.         m_pDvdC = NULL ;
  519.     }
  520.     if (m_pDvdI) {
  521.         m_pDvdI->Release() ;
  522.         m_pDvdI = NULL ;
  523.     }
  524.     if (m_pGraph) {
  525.         m_pGraph->Release() ;
  526.         m_pGraph = NULL ;
  527.     }
  528.     CBaseVideoPlayer::ReleaseInterfaces() ;  // release stanadrd interfaces
  529. }
  530.  
  531.  
  532. //
  533. // CDVDPlayer::GetStatusText(): Composes a status message on failure to build DVD graph.
  534. //
  535. DWORD CDVDPlayer::GetStatusText(AM_DVD_RENDERSTATUS *pStatus,
  536.                                 LPTSTR lpszStatusText,
  537.                                 DWORD dwMaxText)
  538. {
  539.     DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetStatusText() entered"))) ;
  540.     
  541.     TCHAR    achBuffer[1000] ;
  542.     
  543.     if (IsBadWritePtr(lpszStatusText, sizeof(*lpszStatusText) * dwMaxText))
  544.     {
  545.         DbgLog((LOG_ERROR, 0, TEXT("GetStatusText(): bad text buffer param"))) ;
  546.         return 0 ;
  547.     }
  548.     
  549.     int    iChars ;
  550.     LPTSTR lpszBuff = achBuffer ;
  551.     ZeroMemory(achBuffer, sizeof(TCHAR) * 1000) ;
  552.     if (pStatus->iNumStreamsFailed > 0)
  553.     {
  554.         iChars = wsprintf(lpszBuff, 
  555.             TEXT("* %d out of %d DVD-Video streams failed to render properly\n"), 
  556.             pStatus->iNumStreamsFailed, pStatus->iNumStreams) ;
  557.         lpszBuff += iChars ;
  558.         
  559.         if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_VIDEO)
  560.         {
  561.             iChars = wsprintf(lpszBuff, TEXT("    - video stream\n")) ;
  562.             lpszBuff += iChars ;
  563.         }
  564.         if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_AUDIO)
  565.         {
  566.             iChars = wsprintf(lpszBuff, TEXT("    - audio stream\n")) ;
  567.             lpszBuff += iChars ;
  568.         }
  569.         if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_SUBPIC)
  570.         {
  571.             iChars = wsprintf(lpszBuff, TEXT("    - subpicture stream\n")) ;
  572.             lpszBuff += iChars ;
  573.         }
  574.     }
  575.     
  576.     if (FAILED(pStatus->hrVPEStatus))
  577.     {
  578.         lstrcat(lpszBuff, TEXT("* ")) ;
  579.         lpszBuff += lstrlen(TEXT("* ")) ;
  580.         iChars = AMGetErrorText(pStatus->hrVPEStatus, lpszBuff, 200) ;
  581.         lpszBuff += iChars ;
  582.         lstrcat(lpszBuff, TEXT("\n")) ;
  583.         lpszBuff += lstrlen(TEXT("\n")) ;
  584.     }
  585.     
  586.     if (pStatus->bDvdVolInvalid)
  587.     {
  588.         iChars = wsprintf(lpszBuff, TEXT("* Specified DVD-Video volume was invalid\n")) ;
  589.         lpszBuff += iChars ;
  590.     }
  591.     else if (pStatus->bDvdVolUnknown)
  592.     {
  593.         iChars = wsprintf(lpszBuff, TEXT("* No valid DVD-Video volume could be located\n")) ;
  594.         lpszBuff += iChars ;
  595.     }
  596.     
  597.     if (pStatus->bNoLine21In)
  598.     {
  599.         iChars = wsprintf(lpszBuff, TEXT("* The video decoder doesn't produce closed caption data\n")) ;
  600.         lpszBuff += iChars ;
  601.     }
  602.     if (pStatus->bNoLine21Out)
  603.     {
  604.         iChars = wsprintf(lpszBuff, TEXT("* Decoded closed caption data not rendered properly\n")) ;
  605.         lpszBuff += iChars ;
  606.     }
  607.     
  608.     DWORD dwLength = (lpszBuff - achBuffer) * sizeof(*lpszBuff) ;
  609.     dwLength = min(dwLength, dwMaxText) ;
  610.     lstrcpyn(lpszStatusText, achBuffer, dwLength) ;
  611.     
  612.     return dwLength ;
  613. }
  614.  
  615.  
  616.  
  617. //
  618. // CFilePlayer constructor
  619. //
  620. CFilePlayer::CFilePlayer(void)
  621. {
  622.     DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer c-tor entered"))) ;
  623.     
  624.     m_pDDXM = NULL ;
  625. }
  626.  
  627.  
  628. //
  629. // CFilePlayer destructor
  630. //
  631. CFilePlayer::~CFilePlayer(void)
  632. {
  633.     DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer d-tor entered"))) ;
  634.     
  635.     ReleaseInterfaces() ;
  636.     
  637.     DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer d-tor exiting..."))) ;
  638. }
  639.  
  640.  
  641. //
  642. // CFilePlayer::ReleaseInterfaces(): Let go of the interfaces taken in BuildGraph()
  643. //
  644. void CFilePlayer::ReleaseInterfaces(void)
  645. {
  646.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::ReleaseInterfaces() entered"))) ;
  647.     
  648.     if (m_pDDXM) {
  649.         m_pDDXM->Release() ;
  650.         m_pDDXM = NULL ;
  651.     }
  652.     CBaseVideoPlayer::ReleaseInterfaces() ;
  653. }
  654.  
  655.  
  656. //
  657. // CFilePlayer::Initialize(): Creates an empty filter graph object.
  658. //
  659. BOOL CFilePlayer::Initialize(void)
  660. {
  661.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::Initialize() entered"))) ;
  662.     
  663.     //
  664.     // Just instantiate the Filter Graph object
  665.     //
  666.     HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 
  667.         IID_IGraphBuilder, (LPVOID *)&m_pGraph) ;
  668.     if (FAILED(hr) || NULL == m_pGraph)
  669.     {
  670.         DbgLog((LOG_ERROR, 0, 
  671.             TEXT("ERROR: DirectShow is not installed properly (Error 0x%lx)"), hr)) ;
  672.         return FALSE ;
  673.     }
  674.     
  675.     return TRUE;
  676. }
  677.  
  678.  
  679. //
  680. // CFilePlayer::IsOvMConnected(): Private method to detect if the video stream 
  681. // is passing through the Overlay Mixer (i.e, is it connected?).
  682. //
  683. BOOL CFilePlayer::IsOvMConnected(IBaseFilter *pOvM)
  684. {
  685.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::IsOvMConnected() entered"))) ;
  686.     
  687.     IEnumPins   *pEnumPins ;
  688.     IPin        *pPin ;
  689.     IPin        *pPin2 ;
  690.     ULONG        ul ;
  691.     HRESULT      hr ;
  692.     BOOL         bConnected = FALSE ;
  693.  
  694.     pOvM->EnumPins(&pEnumPins) ;
  695.     while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
  696.     {
  697.         hr = pPin->ConnectedTo(&pPin2) ;
  698.         if (SUCCEEDED(hr) && pPin2)
  699.         {
  700.             DbgLog((LOG_TRACE, 3, TEXT("Found pin %s connected to pin %s"), 
  701.                     (LPCTSTR)CDisp(pPin), (LPCTSTR)CDisp(pPin2))) ;
  702.             bConnected = TRUE ;
  703.             pPin2->Release() ;
  704.         }
  705.         pPin->Release() ;
  706.     }
  707.     pEnumPins->Release() ;
  708.     
  709.     return bConnected ;
  710. }
  711.  
  712.  
  713.  
  714. //
  715. // CFilePlayer::GetVideoRendererInterface(): Private method to get the interface
  716. // to the Video Rendererer filter. It also tells us if a file has any video stream.
  717. //
  718. HRESULT CFilePlayer::GetVideoRendererInterface(IBaseFilter **ppVR)
  719. {
  720.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::IsVideoStreamPresent() entered"))) ;
  721.     
  722.     // Get Video Renderer filter pointer from the graph
  723.     return m_pGraph->FindFilterByName(L"Video Renderer", ppVR) ;
  724. }
  725.  
  726.  
  727.  
  728. //
  729. // CFilePlayer::AddOvMToGraph(): Private method to instantiate OverlayMixer,
  730. // add it to the filter graph and set the DDraw parameters specified by the
  731. // app..
  732. //
  733. HRESULT CFilePlayer::AddOvMToGraph(IBaseFilter **ppOvM, LPDIRECTDRAW pDDObj, 
  734.                                    LPDIRECTDRAWSURFACE pDDPrimary)
  735. {
  736.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::AddOvMToGraph() entered"))) ;
  737.     
  738.     HRESULT  hr ;
  739.     
  740.     hr = CoCreateInstance(CLSID_OverlayMixer, NULL, CLSCTX_INPROC, IID_IBaseFilter, (LPVOID *)ppOvM) ;
  741.     if (FAILED(hr) || NULL == *ppOvM)
  742.     {
  743.         DbgLog((LOG_ERROR, 0, TEXT("Can't instantiate Overlay Mixer (Error 0x%lx)"), hr)) ;
  744.         return E_FAIL ;
  745.     }
  746.     hr = m_pGraph->AddFilter(*ppOvM, L"Overlay Mixer") ;
  747.     if (FAILED(hr))
  748.     {
  749.         DbgLog((LOG_ERROR, 0, TEXT("Can't add Overlay Mixer to the graph (Error 0x%lx)"), hr)) ;
  750.         (*ppOvM)->Release() ;
  751.         *ppOvM = NULL ;
  752.         return E_FAIL ;
  753.     }
  754.     
  755.     // Set the DDraw params now
  756.     hr = SetDDrawParams(*ppOvM, pDDObj, pDDPrimary) ;
  757.     if (FAILED(hr))
  758.     {
  759.         m_pGraph->RemoveFilter(*ppOvM) ;  // remove from graph
  760.         (*ppOvM)->Release() ;
  761.         *ppOvM = NULL ;
  762.         return hr ;
  763.     }
  764.     
  765.     return S_OK ;
  766. }
  767.  
  768.  
  769. //
  770. // CFilePlayer::SetDDrawParams(): Private method to set DDraw objeact and primary
  771. // surface on the OverlayMixer via the IDDrawExclModeVideo interface.
  772. //
  773. HRESULT CFilePlayer::SetDDrawParams(IBaseFilter *pOvM, LPDIRECTDRAW pDDObj, 
  774.                                     LPDIRECTDRAWSURFACE pDDPrimary)
  775. {
  776.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetDDrawParams() entered"))) ;
  777.     
  778.     HRESULT                 hr ;
  779.     IDDrawExclModeVideo    *pDDXM ;
  780.     
  781.     hr = pOvM->QueryInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXM) ;
  782.     if (FAILED(hr) || NULL == pDDXM)
  783.     {
  784.         DbgLog((LOG_ERROR, 0, 
  785.             TEXT("Can't get IDDrawExclusiveMode interface from Overlay Mixer (Error 0x%lx)"), hr)) ;
  786.         return E_FAIL ;
  787.     }
  788.     hr = pDDXM->SetDDrawObject(pDDObj) ;
  789.     if (FAILED(hr))
  790.     {
  791.         DbgLog((LOG_ERROR, 0, TEXT("SetDDrawObject(0x%lx) failed (Error 0x%lx)"), pDDObj, hr)) ;
  792.         pDDXM->Release() ;               // release interface
  793.         return E_FAIL ;
  794.     }
  795.     hr = pDDXM->SetDDrawSurface(pDDPrimary) ;
  796.     if (FAILED(hr))
  797.     {
  798.         DbgLog((LOG_ERROR, 0, TEXT("SetDDrawSurface(0x%lx) failed (Error 0x%lx)"), pDDPrimary, hr)) ;
  799.         pDDXM->SetDDrawObject(NULL) ;    // get back to original DDraw object
  800.         pDDXM->Release() ;               // release interface
  801.         return E_FAIL ;
  802.     }
  803.     
  804.     pDDXM->Release() ;               // release interface
  805.     
  806.     return S_OK ;
  807. }
  808.  
  809.  
  810. //
  811. // CFilePlayer::PutVideoThroughOvM(): Private method to connect the decoded video 
  812. // stream through the OverlayMixer.
  813. //
  814. HRESULT CFilePlayer::PutVideoThroughOvM(IBaseFilter *pOvM, IBaseFilter *pVR)
  815. {
  816.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::PutVideoThroughOvM() entered"))) ;
  817.     
  818.     IEnumPins     *pEnumPins ;
  819.     IPin          *pPinVR ;
  820.     IPin          *pPinConnectedTo ;
  821.     IPin          *pPinOvM ;
  822.     ULONG          ul ;
  823.     PIN_DIRECTION  pd ;
  824.     HRESULT        hr ;
  825.     
  826.     // Get the video renderer's (only) in pin
  827.     hr = pVR->EnumPins(&pEnumPins) ;
  828.     ASSERT(SUCCEEDED(hr)) ;
  829.     hr = pEnumPins->Next(1, &pPinVR, &ul) ;
  830.     ASSERT(S_OK == hr  &&  1 == ul)  ;
  831.     pPinVR->QueryDirection(&pd) ;
  832.     ASSERT(PINDIR_INPUT == pd) ;
  833.     pEnumPins->Release() ;
  834.     
  835.     // Disconnect VR from upstream filter and put OvMixer in between them
  836.     hr = pPinVR->ConnectedTo(&pPinConnectedTo) ;
  837.     ASSERT(SUCCEEDED(hr) && pPinConnectedTo) ;
  838.     hr = m_pGraph->Disconnect(pPinVR) ;
  839.     ASSERT(SUCCEEDED(hr)) ;
  840.     hr = m_pGraph->Disconnect(pPinConnectedTo) ;
  841.     ASSERT(SUCCEEDED(hr)) ;
  842.     
  843.     // Now connect the upstream filter's out pin to OvM's in pin 
  844.     // (and remove Video Renderer from the graph).
  845.     hr = pOvM->EnumPins(&pEnumPins) ;
  846.     ASSERT(SUCCEEDED(hr)) ;
  847.     int  iInConns  = 0 ;
  848.     while (iInConns == 0  &&   // input pin not connected yet
  849.         S_OK == pEnumPins->Next(1, &pPinOvM, &ul) && 1 == ul)  // pin left to try
  850.     {
  851.         pPinOvM->QueryDirection(&pd) ;
  852.         if (PINDIR_INPUT == pd)  // OvM's in pin <- Upstream filter's pin
  853.         {
  854.             if (0 == iInConns) // We want to connect only one input pin
  855.             {
  856.                 hr = m_pGraph->Connect(pPinConnectedTo, pPinOvM) ; // , NULL) ;  // direct??
  857.                 ASSERT(SUCCEEDED(hr)) ;
  858.                 if (FAILED(hr))
  859.                     DbgLog((LOG_ERROR, 0, TEXT("ERROR: m_pGraph->Connect() failed (Error 0x%lx)"), hr)) ;
  860.                 else
  861.                 {
  862.                     DbgLog((LOG_TRACE, 5, TEXT("Pin %s connected to pin %s"), 
  863.                         (LPCTSTR) CDisp(pPinConnectedTo), (LPCTSTR) CDisp(pPinOvM))) ;
  864.                     iInConns++ ;
  865.                 }
  866.             }
  867.             // else ignore
  868.         }
  869.         else
  870.             DbgLog((LOG_ERROR, 1, TEXT("OVMixer still has an out pin!!!"))) ;
  871.         
  872.         pPinOvM->Release() ;
  873.     }
  874.     pEnumPins->Release() ;
  875.     
  876.     pPinConnectedTo->Release() ;  // done with upstream pin
  877.     pPinVR->Release() ; // done with VR pin
  878.     m_pGraph->RemoveFilter(pVR) ;  // by force remove the VR from graph
  879.  
  880.     // Just to check...
  881.     if (0 == iInConns)  // input pin not connected!!
  882.     {
  883.         DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't connect any out pin to OvMixer's 1st in pin"))) ;
  884.         return E_FAIL ;    // failure
  885.     }
  886.     
  887.     return S_OK ;          // success!!
  888. }
  889.  
  890.  
  891. //
  892. // CFilePlayer::BuildGraph(): Builds a AVI/MPEG/.. playback graph rendering via
  893. // OverlayMixer which uses app's given DDraw params.
  894. //
  895. HRESULT CFilePlayer::BuildGraph(HWND hWndApp, LPDIRECTDRAW pDDObj, LPDIRECTDRAWSURFACE pDDPrimary)
  896. {
  897.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::BuildGraph() entered"))) ;
  898.     
  899.     HRESULT       hr ;
  900.     IBaseFilter  *pOvM ;
  901.     WCHAR         achwFileName[MAX_PATH] ;
  902.     LPWSTR        lpszwFileName = NULL ;
  903.     IBaseFilter  *pVR ;
  904.     
  905.     // First release any existing interface pointer(s)
  906.     ReleaseInterfaces() ;
  907.     SetColorKey(253) ;  // default magenta for 8bpp
  908.     
  909.     // Check if a file name has been specified; if so, use that
  910.     if (lstrlen(GetFileName()) > 0)  // if something was specified before
  911.     {
  912. #ifdef UNICODE
  913.         lstrcpy(achwFileName, GetFileName()) ;
  914. #else
  915.         MultiByteToWideChar(CP_ACP, 0, GetFileName(), -1, achwFileName, MAX_PATH) ;
  916. #endif // UNICODE
  917.         
  918.         lpszwFileName = achwFileName ;
  919.     }
  920.     else  // no file specified, but we should have detected it before!!!
  921.         return E_FAIL ;
  922.     
  923.     //
  924.     // Instantiate Overlay Mixer, add it to the graph and set DDraw params
  925.     //
  926.     hr = AddOvMToGraph(&pOvM, pDDObj, pDDPrimary) ;
  927.     if (FAILED(hr))
  928.     {
  929.         return E_FAIL ;
  930.     }
  931.     
  932.     //
  933.     // First render the graph for the selected file
  934.     //
  935.     hr = m_pGraph->RenderFile(lpszwFileName, NULL) ;
  936.     if (S_OK != hr)
  937.     {
  938.         DbgLog((LOG_ERROR, 0, 
  939.             TEXT("Rendering the given file didn't succeed completely (Error 0x%lx)"), hr)) ;
  940.         m_pGraph->RemoveFilter(pOvM) ;  // remove from graph
  941.         pOvM->Release() ;               // release filter
  942.         return E_FAIL ;
  943.     }
  944.  
  945.     //
  946.     // Because there are some AVI files which on some machines decide to rather go 
  947.     // through the Color Space Converter filter, just making sure that the OverlayMixer
  948.     // is actually being used.  Otherwise we have to do some more (bull)work.
  949.     //
  950.     if (! IsOvMConnected(pOvM) )
  951.     {
  952.         DbgLog((LOG_TRACE, 1, TEXT("OverlayMixer is not used in the graph. Try again..."))) ;
  953.     
  954.         //
  955.         // Check that the  specified file has a video stream. Otherwise OverlayMixer
  956.         // will never be used and DDraw exclusive mode playback doesn't make any sense.
  957.         //
  958.         if (FAILED(GetVideoRendererInterface(&pVR)))
  959.         {
  960.             DbgLog((LOG_TRACE, 1, TEXT("Specified file doesn't have any video stream. Aborting graph building."))) ;
  961.             m_pGraph->RemoveFilter(pOvM) ;  // remove from graph
  962.             pOvM->Release() ;               // release filter
  963.             return E_FAIL ;
  964.         }
  965.  
  966.         //
  967.         // Put the video stream to go through the OverlayMixer.
  968.         //
  969.         hr = PutVideoThroughOvM(pOvM, pVR) ;
  970.         if (FAILED(hr))
  971.         {
  972.             DbgLog((LOG_TRACE, 1, TEXT("Couldn't put video through the OverlayMixer."))) ;
  973.             m_pGraph->RemoveFilter(pOvM) ;  // remove OvMixer from graph
  974.             pOvM->Release() ;               // release OvMixer filter
  975.             pVR->Release() ;                // release VR interface (before giving up)
  976.             return E_FAIL ;
  977.         }
  978.         pVR->Release() ;    // done with VR interface
  979.     }
  980.  
  981.     //
  982.     // We are successful in building the graph. Now the rest...
  983.     //
  984.     GetInterfaces(hWndApp) ;
  985.     
  986.     // Get IDDrawExclModeVideo interface of the OvMixer and store it
  987.     hr = pOvM->QueryInterface(IID_IDDrawExclModeVideo, (LPVOID *)&m_pDDXM) ;
  988.     ASSERT(SUCCEEDED(hr)) ;
  989.     
  990.     // Get the color key to be used and store it
  991.     hr = GetColorKeyInternal(pOvM) ;
  992.     ASSERT(SUCCEEDED(hr)) ;
  993.     
  994.     pOvM->Release() ;  // done with it
  995.     
  996.     return S_OK ;
  997. }
  998.  
  999.  
  1000. //
  1001. // CFilePlayer::GetInterfaces(): Gets some interfaces useful for DVD title playback
  1002. //
  1003. // NOTE: Don't really need this one.  We could have as well used the base classes'.
  1004. //
  1005. HRESULT CFilePlayer::GetInterfaces(HWND hWndApp)
  1006. {
  1007.     return CBaseVideoPlayer::GetInterfaces(hWndApp) ;  // get the standard interfaces
  1008. }
  1009.  
  1010. //
  1011. // CFilePlayer::GetColorKeyInternal(): Private method to query the color key
  1012. // value from teh first input pin of the OverlayMixer.
  1013. //
  1014. HRESULT CFilePlayer::GetColorKeyInternal(IBaseFilter *pOvM)
  1015. {
  1016.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::GetColorKeyInternal() entered"))) ;
  1017.     
  1018.     if (NULL == pOvM)
  1019.         return E_INVALIDARG ;
  1020.     
  1021.     IEnumPins  *pEnumPins ;
  1022.     IPin       *pPin ;
  1023.     ULONG       ul ;
  1024.     PIN_DIRECTION  pd ;
  1025.     DWORD       dwColorKey ;
  1026.     IMixerPinConfig  *pMPC ;
  1027.     HRESULT  hr = pOvM->EnumPins(&pEnumPins) ;
  1028.     ASSERT(pEnumPins) ;
  1029.     while (S_OK == pEnumPins->Next(1, &pPin, &ul)  &&  1 == ul)  // try all pins
  1030.     {
  1031.         pPin->QueryDirection(&pd) ;
  1032.         if (PINDIR_INPUT == pd)  // only the 1st in pin
  1033.         {
  1034.             hr = pPin->QueryInterface(IID_IMixerPinConfig, (LPVOID *) &pMPC) ;
  1035.             ASSERT(SUCCEEDED(hr) && pMPC) ;
  1036.             hr = pMPC->GetColorKey(NULL, &dwColorKey) ;  // just get the physical color
  1037.             SetColorKey(dwColorKey) ;
  1038.             //  Set mode to stretch - that way we don't fight the overlay
  1039.             //  mixer about the exact way to fix the aspect ratio
  1040.             pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED);
  1041.             ASSERT(SUCCEEDED(hr)) ;
  1042.             pMPC->Release() ;
  1043.             pPin->Release() ; // exiting early; release pin
  1044.             break ;   // we are done
  1045.         }
  1046.         pPin->Release() ;
  1047.     }
  1048.     pEnumPins->Release() ;  // done with pin enum
  1049.     
  1050.     return S_OK ;
  1051. }
  1052.  
  1053.  
  1054. //
  1055. // CFilePlayer::ClearGraph(): Releases the filter graph built by BuildGraph()
  1056. // and the interfaces taken for playback.
  1057. //
  1058. HRESULT CFilePlayer::ClearGraph(void)
  1059. {
  1060.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::ClearGraph() entered"))) ;
  1061.     
  1062.     ReleaseInterfaces() ;  // let go of the other interfaces
  1063.     if (m_pGraph)
  1064.     {
  1065.         m_pGraph->Release() ;  // let the graph go (we'll create a fresh one next time)
  1066.         m_pGraph = NULL ;
  1067.     }
  1068.     
  1069.     return S_OK ;
  1070. }
  1071.  
  1072. //
  1073. // CFilePlayer::SetVideoPosition(): Sets the source and dest rects for the video to
  1074. // be shown via IDDrawExclModeVideo interface of OverlayMixer.
  1075. //
  1076. HRESULT CFilePlayer::SetVideoPosition(DWORD dwLeft, DWORD dwTop, DWORD dwWidth, DWORD dwHeight)
  1077. {
  1078.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetVideoPosition() entered"))) ;
  1079.     
  1080.     RECT  rectDest ;
  1081.     SetRect(&rectDest, dwLeft, dwTop, dwLeft + dwWidth, dwTop + dwHeight) ;
  1082.     
  1083.     // NULL or (0, 0, 10000, 10000) for full video
  1084.     return m_pDDXM->SetDrawParameters(NULL, &rectDest) ;
  1085. }
  1086.  
  1087.  
  1088. //
  1089. // CFilePlayer::GetNativeVideoData(): Returns the actual video size to the app.
  1090. //
  1091. HRESULT CFilePlayer::GetNativeVideoData(DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwARX, DWORD *pdwARY)
  1092. {
  1093.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::GetNativeVideoData() entered"))) ;
  1094.     
  1095.     return m_pDDXM->GetNativeVideoProps(pdwWidth, pdwHeight, pdwARX, pdwARY) ;
  1096. }
  1097.  
  1098.  
  1099. //
  1100. // CFilePlayer::SetOverlayCallback(): Specify the pointer to the overlay notification
  1101. // callback object which the OverlayMixer will call during playback.
  1102. //
  1103. HRESULT CFilePlayer::SetOverlayCallback(IDDrawExclModeVideoCallback *pCallback)
  1104. {
  1105.     DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetOverlayCallback() entered"))) ;
  1106.  
  1107.     HRESULT  hr ;
  1108.     hr = m_pDDXM->SetCallbackInterface(pCallback, 0) ;
  1109.     if (FAILED(hr))
  1110.     {
  1111.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetCallbackInterface() failed (Error 0x%lx)"), hr)) ;
  1112.     }
  1113.  
  1114.     return hr ;
  1115. }
  1116.  
  1117.  
  1118.